﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Text;
using System.Web.Caching;
using System.Collections;
using System.Text.RegularExpressions;
using Newtonsoft.Json;

namespace kmer.Web {
	/// <summary>
	/// 缓存类
	/// 2009-11-20 重写 FW 4.0
	/// </summary>
	public static class myCache {
		// Fields
		private static readonly Cache _cache;
		public static readonly int DayFactor = 86400;
		public static readonly int HourFactor = 3600;
		public static readonly int MinuteFactor = 60;

		// Methods
		static myCache() {
			HttpContext context = HttpContext.Current;
			if (context != null) {
				_cache = context.Cache;
			} else {
				_cache = HttpRuntime.Cache;
			}
		}

		/// <summary>
		/// 缓存文本文件
		/// 目标文件发生改变时会导致缓存删除
		/// </summary>
		/// <param name="key"></param>
		/// <param name="filePath"></param>
		/// <returns>文本文件内容</returns>
		public static string CacheFile(string key, string filePath) {
			//filePath = myContext.Current.MapPath(filePath);
			filePath = System.Web.HttpContext.Current.Server.MapPath(filePath);
			if (System.IO.File.Exists(filePath)) {
				StreamReader sr = new StreamReader(filePath, Encoding.UTF8);
				string fileBody = sr.ReadToEnd();
				sr.Close();
				CacheDependency dep = new CacheDependency(filePath);
				Max(key, fileBody, dep);
				return fileBody;
			} else {
				return string.Empty;
			}
		}

		public static void Clear() {
			IDictionaryEnumerator CacheEnum = _cache.GetEnumerator();
			while (CacheEnum.MoveNext()) {
				_cache.Remove(CacheEnum.Key.ToString());
			}
		}

		public static bool Exists(string Key) {
			return (_cache[Key] != null);
		}

		public static object Get(string key) {
			return _cache[key];
		}
		/// <summary>
		/// 读取缓存，匹配正则表达式
		/// </summary>
		/// <param name="pattern"></param>
		/// <returns></returns>
		public static ArrayList GetByPattern(string pattern) {
			ArrayList result = new ArrayList();
			IDictionaryEnumerator CacheEnum = _cache.GetEnumerator();
			Regex regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
			while (CacheEnum.MoveNext()) {
				if (regex.IsMatch(CacheEnum.Key.ToString())) {
					result.Add(_cache[CacheEnum.Key.ToString()]);
				}
			}
			return result;
		}
		public static Dictionary<string, object> Search(string pattern) {
			var result = new Dictionary<string, object>();
			var cacheEnum = _cache.GetEnumerator();
			var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
			while (cacheEnum.MoveNext()) {
				if (regex.IsMatch(cacheEnum.Key.ToString())) {
					result.Add(cacheEnum.Key.ToString(), _cache[cacheEnum.Key.ToString()]);
				}
			}
			return result;
		}
		/// <summary>
		/// 计算缓存数量
		/// </summary>
		/// <param name="pattern"></param>
		/// <returns></returns>
		public static int CountCache(string pattern) {
			IDictionaryEnumerator CacheEnum = _cache.GetEnumerator();
			Regex regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
			int c = 0;
			while (CacheEnum.MoveNext()) {
				if (regex.IsMatch(CacheEnum.Key.ToString())) {
					c++;
				}
			}
			return c;
		}
		/// <summary>
		/// 读取缓存中的文本文件内容
		/// 如果缓存无效，该方法会自动读取磁盘文件并缓存
		/// </summary>
		/// <param name="key"></param>
		/// <param name="filePath"></param>
		/// <returns></returns>
		public static string GetFile(string key, string filePath) {
			if (Exists(key)) {
				return Get(key).ToString();
			}
			return CacheFile(key, filePath);
		}
		/// <summary>
		/// 读取缓存中的文件并且反系列化为指定对象
		/// JSON格式的
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="key"></param>
		/// <param name="filePath"></param>
		/// <returns></returns>
		public static T GetFile<T>(string key, string filePath) {
			var str = GetFile(key, filePath);
			return JsonConvert.DeserializeObject<T>(str);
		}
		#region 重载Get简化
		public static int Get(string Key, int dv=0) {
			if (_cache[Key] != null) {
				return (int)_cache[Key];
			}
			return dv;
		}
		public static string Get(string Key, string dv="") {
			if (_cache[Key] != null) {
				return _cache[Key].ToString();
			}
			return dv;
		}
		public static DateTime GetDate(string Key, DateTime dv) {
			if (_cache[Key] != null) {
				return (DateTime)_cache[Key];
			}
			return dv;
		}
		/// <summary>
		/// 从缓存中读取数据，如果没有该值则返回default(T)
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="Key"></param>
		/// <returns></returns>
		public static T Get<T>(string Key) {
			if (_cache[Key] != null) {
				return (T)_cache[Key];
			}
			return default(T);
		}
		/// <summary>
		/// 读取缓存，如果缓存中没有该值，则使用默认值
		/// 对于复杂的数据类型，不建议使用
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="Key"></param>
		/// <param name="dv"></param>
		/// <returns></returns>
		public static T Get<T>(string Key, T dv) {
			if (_cache[Key] != null) {
				return (T)_cache[Key];
			}
			return dv;
		}
		#endregion
		/// <summary>
		/// 添加缓存
		/// 等价于Max(string,object);
		/// </summary>
		/// <seealso cref="Max"/>
		/// <param name="key"></param>
		/// <param name="obj"></param>
		public static object Insert(string key, object obj) {
			return Max(key, obj);
		}
		public static T Insert<T>(string key, T obj) {
			return Max(key, obj);
		}
		/// <summary>
		/// 添加缓存（设置过期日期）
		/// </summary>
		/// <param name="key"></param>
		/// <param name="obj"></param>
		/// <param name="Date">过期日期</param>
		public static object Insert(string key, object obj, DateTime Date) {
			if (obj != null) {
				_cache.Insert(key, obj, null, Date, TimeSpan.Zero);
			}
			return obj;
		}
		public static T Insert<T>(string key, T obj, DateTime Date) {
			if (obj != null) {
				_cache.Insert(key, obj, null, Date, TimeSpan.Zero);
			}
			return obj;
		}

		/// <summary>
		/// 添加缓存
		/// 过期时间：12小时
		/// </summary>
		/// <param name="key"></param>
		/// <param name="obj"></param>
		/// <param name="dep">依赖关系</param>
		public static object Insert(string key, object obj, CacheDependency dep) {
			return Insert(key, obj, HourFactor * 12, dep);
		}
		public static T Insert<T>(string key, T obj, CacheDependency dep) {
			return Insert(key, obj, HourFactor * 12, dep);
		}
		/// <summary>
		/// 添加缓存
		/// </summary>
		/// <param name="key"></param>
		/// <param name="obj"></param>
		/// <param name="seconds">过期时间（秒）</param>
		/// <param name="priority">处理级别</param>
		public static object Insert(string key, object obj, int seconds, CacheItemPriority priority) {
			return Insert(key, obj, seconds, null, priority);
		}
		public static T Insert<T>(string key, T obj, int seconds, CacheItemPriority priority) {
			return Insert(key, obj, seconds, null, priority);
		}
		/// <summary>
		/// 添加缓存
		/// </summary>
		/// <param name="key"></param>
		/// <param name="obj"></param>
		/// <param name="dep">依赖关系</param>
		/// <param name="seconds">过期时间（秒）</param>
		/// <param name="priority">处理级别</param>
		public static object Insert(string key, object obj, int seconds, CacheDependency dep = null, CacheItemPriority priority = CacheItemPriority.Normal) {
			if (obj != null) {
				_cache.Insert(key, obj, dep, DateTime.Now.AddSeconds((double)(seconds)), TimeSpan.Zero, priority, null);
			}
			return obj;
		}
		public static T Insert<T>(string key, T obj, int seconds, CacheDependency dep = null, CacheItemPriority priority = CacheItemPriority.Normal) {
			if (obj != null) {
				_cache.Insert(key, obj, dep, DateTime.Now.AddSeconds((double)(seconds)), TimeSpan.Zero, priority, null);
			}
			return obj;
		}
		/// <summary>
		/// 永久缓存
		/// </summary>
		/// <param name="key"></param>
		/// <param name="obj"></param>
		public static object Max(string key, object obj) {
			return Max(key, obj, null);
		}
		public static T Max<T>(string key, T obj) {
			return Max(key, obj, null);
		}
		/// <summary>
		/// 永久缓存，依赖关系可能导致缓存清理
		/// </summary>
		/// <param name="key"></param>
		/// <param name="obj"></param>
		/// <param name="dep">依赖关系</param>
		public static object Max(string key, object obj, CacheDependency dep) {
			if (obj != null) {
				_cache.Insert(key, obj, dep, DateTime.MaxValue, TimeSpan.Zero, CacheItemPriority.High, null);
			}
			return obj;
		}
		public static T Max<T>(string key, T obj, CacheDependency dep) {
			if (obj != null) {
				_cache.Insert(key, obj, dep, DateTime.MaxValue, TimeSpan.Zero, CacheItemPriority.High, null);
			}
			return obj;
		}

		public static object MicroInsert(string key, object obj, int secondFactor) {
			if (obj != null) {
				_cache.Insert(key, obj, null, DateTime.Now.AddSeconds((double)(secondFactor)), TimeSpan.Zero);
			}
			return obj;
		}
		public static T MicroInsert<T>(string key, T obj, int secondFactor) {
			if (obj != null) {
				_cache.Insert(key, obj, null, DateTime.Now.AddSeconds((double)(secondFactor)), TimeSpan.Zero);
			}
			return obj;
		}

		public static void Remove(string key) {
			_cache.Remove(key);
		}
		public static IDictionaryEnumerator GetEnumerator() {
			return _cache.GetEnumerator();
		}
		public static int RemoveByPattern(string pattern) {
			IDictionaryEnumerator CacheEnum = _cache.GetEnumerator();
			Regex regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
			var count = 0;
			while (CacheEnum.MoveNext()) {
				if (regex.IsMatch(CacheEnum.Key.ToString())) {
					_cache.Remove(CacheEnum.Key.ToString());
					count++;
				}
			}
			return count;
		}
		public static string GetCacheType(IDictionaryEnumerator CacheEnum) {
			if (CacheEnum.Value is string) {
				return string.Format("String({0})", CacheEnum.Value.ToString().Length);
			} else if (CacheEnum.Value is ICollection) {
				return string.Format("{0}(Length={1})", CacheEnum.Value.GetType(), (CacheEnum.Value as ICollection).Count);
			}
			return CacheEnum.Value.GetType().ToString();
		}

		public static int RemoveByPattern(string pattern, params object[] args) {
			int count = 0;
			if (args != null) {
				count = RemoveByPattern(string.Format(pattern, args));
			} else {
				count = RemoveByPattern(pattern);
			}
			return count;
		}

		public static object Set(string key, object obj) {
			if (Exists(key)) {
				_cache[key] = obj;
			}
			return obj;
		}
		public static T Set<T>(string key, T obj) {
			if (Exists(key)) {
				_cache[key] = obj;
			}
			return obj;
		}
	}
}